/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

/*************************** 常量定义 ********************************/
// 定义以太网帧类型
const bit<16> TYPE_IPV4 = 0x800;
const bit<16> TYPE_ARP  = 0x0806;
// ARP 协议相关常量
const bit<16> ARP_HTYPE_ETHERNET = 0x0001;
const bit<16> ARP_PTYPE_IPV4     = 0x0800;
const bit<8>  ARP_HLEN_ETHERNET  = 6;
const bit<8>  ARP_PLEN_IPV4      = 4;
const bit<16> ARP_OPER_REQUEST   = 1;
const bit<16> ARP_OPER_REPLY     = 2;
/*************************** 头部定义 ********************************/
typedef bit<9>  egressSpec_t;   // 出口端口标识（9位）
typedef bit<48> macAddr_t;      // MAC 地址（48位）
typedef bit<32> ip4Addr_t;      // IPv4 地址（32位）


header ethernet_t {
    macAddr_t dstAddr;  // 目的 MAC 地址
    macAddr_t srcAddr;  // 源 MAC 地址
    bit<16>   etherType; // 上层协议类型（如IPv4/ARP）
}

// IPv4 头部
header ipv4_t {
    bit<4>    version;
    bit<4>    ihl;
    bit<8>    diffserv;
    bit<16>   totalLen;
    bit<16>   identification;
    bit<3>    flags;
    bit<13>   fragOffset;
    bit<8>    ttl;
    bit<8>    protocol;
    bit<16>   hdrChecksum;
    ip4Addr_t srcAddr;
    ip4Addr_t dstAddr;
}

// ARP 头部（仅用于ARP协议）
header arp_t {
    bit<16> htype;         // 硬件类型（如以太网）
    bit<16> ptype;         // 协议类型（如IPv4）
    bit<8> hlen;          // 硬件地址长度
    bit<8> plen;          // 协议地址长度
    bit<16> oper;          // 操作码（请求/响应）
    macAddr_t srcMACAddr;  // 发送方 MAC 地址
    ip4Addr_t srcIPAddr;   // 发送方 IP 地址
    macAddr_t dstMACAddr;  // 目标方 MAC 地址
    ip4Addr_t dstIPAddr;   // 目标方 IP 地址
}

/*************************** 元数据和头部集合 ************************/
struct metadata {
    ip4Addr_t  dst_ipv4;  // 存储目标 IP 地址（用于ARP处理）
}

struct headers {
    ethernet_t   ethernet; // 以太网头部
    ipv4_t       ipv4;     // IPv4 头部
    arp_t        arp;      // ARP 头部
}

/*************************** 解析器 **********************************/
parser MyParser(
    packet_in packet,      // 输入数据包
    out headers hdr,       // 解析后的头部集合
    inout metadata meta,   // 元数据
    inout standard_metadata_t standard_metadata // 标准元数据
) {
    state start {
        transition par_ether; // 初始状态：解析以太网头部
    }

    state par_ether {
        packet.extract(hdr.ethernet); // 提取以太网头部
        transition select(hdr.ethernet.etherType) {
            TYPE_IPV4: par_ipv4;     // 若为IPv4，跳转到IPv4解析
            TYPE_ARP : parse_arp;    // 若为ARP，跳转到ARP解析
            default: accept;         // 其他协议直接接受
        }
    }

    state par_ipv4 {
        packet.extract(hdr.ipv4);    // 提取IPv4头部
        transition accept;           // 结束解析
    }

    state parse_arp {
        packet.extract(hdr.arp);     // 提取ARP头部
        meta.dst_ipv4 = hdr.arp.dstIPAddr; // 将ARP目标IP存入元数据
        transition accept;           // 结束解析
    }
}

/*************************** 校验和验证 ******************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply { }
}

/*************************** 入口处理 *******************************/
control MyIngress(
    inout headers hdr,
    inout metadata meta,
    inout standard_metadata_t standard_metadata
) {
    // 动作：丢弃数据包
    action drop() {
        mark_to_drop(standard_metadata); // 标记数据包为丢弃
    }
    action ipv4_forward(egressSpec_t port, macAddr_t dstAddr) {
        standard_metadata.egress_spec = port; // 设置出口端口
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr; // 交换MAC地址（源->目的）
        hdr.ethernet.dstAddr = dstAddr;       // 设置新目的MAC
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;     // TTL减1
    }

    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: lpm;
	}
        actions = {
            ipv4_forward; // 转发
            drop;         // 丢弃
            NoAction;     // 无操作
        }
        size = 1024;                // 表大小
        default_action = NoAction(); // 默认无操作
    }

    action send_arp_reply(macAddr_t macAddr, ip4Addr_t IPAddr) {
        hdr.ethernet.dstAddr = hdr.arp.srcMACAddr; // 目的MAC设为请求方MAC
        hdr.ethernet.srcAddr = macAddr;             // 源MAC设为自身MAC
        hdr.arp.oper = ARP_OPER_REPLY;             // 操作码改为响应
        hdr.arp.dstMACAddr = hdr.arp.srcMACAddr;    // 目标MAC设为请求方MAC
        hdr.arp.dstIPAddr = hdr.arp.srcIPAddr;      // 目标IP设为请求方IP
        hdr.arp.srcMACAddr = macAddr;               // 源MAC设为自身MAC
        hdr.arp.srcIPAddr = IPAddr;                 // 源IP设为自身IP
        standard_metadata.egress_spec = standard_metadata.ingress_port;
    }

    table arp_ternary {
        key = {
            hdr.arp.oper : exact;       // 精确匹配操作码
            hdr.arp.dstIPAddr : lpm;    // 最长前缀匹配目标IP
        }
        actions = {
            send_arp_reply; // 发送ARP响应
            drop;           // 丢弃
        }
        const default_action = drop(); // 默认丢弃
    }

    apply {
        if (hdr.ethernet.etherType == TYPE_IPV4) {
            ipv4_lpm.apply(); // IPv4转发
        } else if (hdr.ethernet.etherType == TYPE_ARP) {
            arp_ternary.apply(); // ARP处理
        }
    }
}

/*************************** 出口处理 *******************************/
control MyEgress(
    inout headers hdr,
    inout metadata meta,
    inout standard_metadata_t standard_metadata
) {
    apply { }
}

/*************************** 校验和计算 ****************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
    apply {
        update_checksum(
            hdr.ipv4.isValid(),
            { hdr.ipv4.version, hdr.ipv4.ihl,
              hdr.ipv4.diffserv, hdr.ipv4.totalLen,
              hdr.ipv4.identification, hdr.ipv4.flags,
              hdr.ipv4.fragOffset, hdr.ipv4.ttl,
              hdr.ipv4.protocol, hdr.ipv4.srcAddr,
              hdr.ipv4.dstAddr },
            hdr.ipv4.hdrChecksum,
            HashAlgorithm.csum16
        );
    }
}

/*************************** 反解析器 ******************************/
control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.arp);
        packet.emit(hdr.ipv4);
    }
}

/*************************** 交换机主程序 ***************************/
V1Switch(
    MyParser(),
    MyVerifyChecksum(),
    MyIngress(),
    MyEgress(),
    MyComputeChecksum(),
    MyDeparser()
) main;
